using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace ExcelRefresh.Com
{
    public sealed class OutOfProcess<T> : IDisposable
        where T : class
    {
        public readonly Process Process;
        private readonly OleMessageFilter _filter;
        public T Reference { get; private set; }

        public OutOfProcess(T excelApp, Func<T, int> fnGethWnd)
        {
            Reference = excelApp;
            var hWnd = fnGethWnd(excelApp);
            int processId;
            GetWindowThreadProcessId(hWnd, out processId);
            Process = Process.GetProcessById(processId);
            _filter = new OleMessageFilter();
        }

        public void Dispose()
        {
            if (Reference == null) return;
            while (Marshal.ReleaseComObject(Reference) > 0) { }
            Reference = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.GetTotalMemory(true);

            _filter.Dispose();

            if (!Process.HasExited)
                Process.Kill();
        }

        [DllImport("user32.dll")]
        static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
    }

}